package com.iwinding.ladygg.bluetooth.impblekit;

import android.app.Activity;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGattCharacteristic;
import android.content.Context;
import android.text.TextUtils;
import android.util.Log;
import android.widget.Toast;

import com.iwinding.ladygg.AppForegroundStateManager;
import com.iwinding.ladygg.R;
import com.iwinding.ladygg.bluetooth.bean.BleDevice;
import com.iwinding.ladygg.bluetooth.ibluetooth.IAutoBlelimit;
import com.iwinding.ladygg.bluetooth.ibluetooth.IBleFunction;
import com.iwinding.ladygg.bluetooth.ibluetooth.IBleListener;
import com.iwinding.ladygg.bluetooth.ibluetooth.IHandler;
import com.iwinding.ladygg.utils.ClsUtils;
import com.iwinding.ladygg.utils.HexStringUtil;
import com.iwinding.ladygg.utils.LogUtil;
import com.iwinding.ladygg.utils.ToastUtil;
import com.inuker.bluetooth.library.BluetoothClient;
import com.inuker.bluetooth.library.beacon.Beacon;
import com.inuker.bluetooth.library.connect.listener.BleConnectStatusListener;
import com.inuker.bluetooth.library.connect.listener.BluetoothStateListener;
import com.inuker.bluetooth.library.connect.options.BleConnectOptions;
import com.inuker.bluetooth.library.connect.response.BleConnectResponse;
import com.inuker.bluetooth.library.connect.response.BleNotifyResponse;
import com.inuker.bluetooth.library.connect.response.BleReadRssiResponse;
import com.inuker.bluetooth.library.connect.response.BleUnnotifyResponse;
import com.inuker.bluetooth.library.connect.response.BleWriteResponse;
import com.inuker.bluetooth.library.model.BleGattProfile;
import com.inuker.bluetooth.library.receiver.listener.BluetoothBondListener;
import com.inuker.bluetooth.library.search.SearchRequest;
import com.inuker.bluetooth.library.search.SearchResult;
import com.inuker.bluetooth.library.search.response.SearchResponse;
import com.inuker.bluetooth.library.utils.BluetoothLog;

import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

import static com.inuker.bluetooth.library.Constants.BLE_NOT_SUPPORTED;
import static com.inuker.bluetooth.library.Constants.REQUEST_SUCCESS;
import static com.inuker.bluetooth.library.Constants.STATUS_CONNECTED;
import static com.inuker.bluetooth.library.Constants.STATUS_DEVICE_CONNECTED;
import static com.inuker.bluetooth.library.Constants.STATUS_DISCONNECTED;

/**
 * Created by 82218 on 2017/7/13.
 */

public class BleKitManager implements IBleFunction {

    private static final String TAG = BleKitManager.class.getSimpleName();

    /**
     * 内部类实现单例模式
     * 延迟加载，减少内存开销
     *
     * @author xuzhaohu
     */
    private static class SingletonHolder {
        private static BleKitManager instance = new BleKitManager();
    }

    public BleKitManager() {
        mHandler = new BleKitHandler();
        deviceList = new ArrayList<>();
    }

    public static BleKitManager getInstance() {
        return BleKitManager.SingletonHolder.instance;
    }

    private Context mApplicationContext;
    private BluetoothClient mClient;
    private IAutoBlelimit autoLimit;

    private String mConnRssi;//当前连接设备信号
    private String connDeviceName;//当前连接设备名称
    private String connDeviceAddress;//当前连接设备地址
    private List<BleDevice> deviceList;//设备列表
    private List<BleDevice> isConedList = new ArrayList<>();

    private BleKitHandler mHandler;

    private boolean isOpen = false;

    private IBleListener iBleListener;

    public void setiBleListener(IBleListener iBleListener) {
        this.iBleListener = iBleListener;
    }

    @Override
    public void initBle(Context application) {
        if (mClient == null) {
            mApplicationContext = application.getApplicationContext();
            mClient = new BluetoothClient(mApplicationContext);
        }
        mHandler.removeMessages(SERVICE_BIND);
        mHandler.sendEmptyMessage(SERVICE_BIND);
    }

    public List<BleDevice> getDeviceList() {
        return deviceList;
    }

    public void reset() {
        if (mClient == null) {
            mClient = new BluetoothClient(mApplicationContext);
        }
        mHandler.removeMessages(SERVICE_BIND);
        mHandler.sendEmptyMessage(SERVICE_BIND);
    }

    @Override
    public void setAutoConnBle(IAutoBlelimit blelimit) {
        autoLimit = blelimit;
    }

    @Override
    public void openBle() {
        if (mClient == null) {
            return;
        }
        mClient.registerBluetoothStateListener(mBluetoothStateListener);
        if (mClient.isBluetoothOpened()) {
            isOpen = true;
            mHandler.removeMessages(SERVICE_OPEN);
            mHandler.sendEmptyMessage(SERVICE_OPEN);
        } else {
            mClient.openBluetooth();
        }
    }

    @Override
    public void scanBle() {
        if (mClient == null) {
            return;
        }
//        deviceList.clear();
        if (null != iBleListener) {
            iBleListener.onStartScan();
        }

        SearchRequest request = new SearchRequest.Builder()
                .searchBluetoothLeDevice(2000, 2)   // 先扫BLE设备3次，每次3s
                .searchBluetoothClassicDevice(1000) // 再扫经典蓝牙5s
                .searchBluetoothLeDevice(1000)      // 再扫BLE设备2s
                .build();

        mClient.search(request, new SearchResponse() {
            @Override
            public void onSearchStarted() {
                mConnRssi = "";
                connDeviceName = "";
                connDeviceAddress = "";
            }

            @Override
            public void onDeviceFounded(SearchResult device) {
                Beacon beacon = new Beacon(device.scanRecord);
                BluetoothLog.v(String.format("beacon for %s\n%s", device.getAddress(), beacon.toString()));

                boolean isHas = false;
                for (BleDevice bleDevice : deviceList) {
                    if (bleDevice.deviceAddress.equals(device.getAddress())) {
                        isHas = true;
                        break;
                    }
                }
                if (!isHas) {
                    BleDevice bleDevice = new BleDevice();
                    bleDevice.deviceName = device.getName();
                    bleDevice.deviceAddress = device.getAddress();
                    bleDevice.deviceRssi = String.valueOf(device.rssi);
                    bleDevice.isConnect = false;

                    LogUtil.i("@hzy", "BleDevice----------deviceName:" + bleDevice.deviceName);
                    LogUtil.i("@hzy", "BleDevice----------deviceAddress:" + bleDevice.deviceAddress);
                    LogUtil.i("@hzy", "BleDevice----------deviceRssi:" + bleDevice.deviceRssi);
                    LogUtil.i("@hzy", "BleDevice----------isConnect:" + bleDevice.isConnect);
                    LogUtil.i("@hzy", "scanBle-------------------add");
                    deviceList.add(bleDevice);
                    mHandler.removeMessages(IBleFunction.ACTION_FOUND);
                    mHandler.sendEmptyMessage(IBleFunction.ACTION_FOUND);
                }
            }

            @Override
            public void onSearchStopped() {
                if (null != iBleListener) {
                    iBleListener.onScanFinish(deviceList);
                }
                mHandler.removeMessages(IBleFunction.SCAN_FINSH);
                mHandler.sendEmptyMessage(IBleFunction.SCAN_FINSH);
            }

            @Override
            public void onSearchCanceled() {
                if (null != iBleListener) {
                    iBleListener.onScanFinish(deviceList);
                }
                mHandler.removeMessages(IBleFunction.SCAN_FINSH);
                mHandler.sendEmptyMessage(IBleFunction.SCAN_FINSH);
            }
        });
    }

    @Override
    public void stopScanBle() {
        if (mClient == null) {
            return;
        }
        mClient.stopSearch();
    }

    @Override
    public void connetBle(String address) {
        if (mClient == null) {
            return;
        }
        if (!isOpen) {
            openBle();
            return;
        }
        if (!TextUtils.isEmpty(connDeviceAddress) || !TextUtils.equals(connDeviceAddress, address)) {
            //判断是否连接状态，连接状态则将当前连接断开
            disConnetBle();
        }
        connDeviceAddress = address;
        mClient.registerBluetoothBondListener(mBluetoothBondListener);
        mClient.registerConnectStatusListener(connDeviceAddress, mBleConnectStatusListener);
        BleConnectOptions options = new BleConnectOptions.Builder()
                .setConnectRetry(3)   // 连接如果失败重试3次
                .setConnectTimeout(30000)   // 连接超时30s
                .setServiceDiscoverRetry(3)  // 发现服务如果失败重试3次
                .setServiceDiscoverTimeout(20000)  // 发现服务超时20s
                .build();
        mClient.connect(address, options, new BleConnectResponse() {
            @Override
            public void onResponse(int code, BleGattProfile profile) {
                if (code == REQUEST_SUCCESS) {
                    for (BleDevice device : deviceList) {
                        if (TextUtils.equals(device.deviceAddress, connDeviceAddress)) {
                            device.isConnect = true;
                            if (autoLimit != null) {
                                autoLimit.setActiveBleDevice(device, true);
                                autoLimit.connDoSomethings(device, profile);
                            }
                            if (null != device) {
                                if (null != iBleListener) {
                                    iBleListener.onConnected(device);
                                }
                            }
                        }
                    }
                    mHandler.removeMessages(SERVICE_SHOW);
                    mHandler.sendEmptyMessage(SERVICE_SHOW);
                } else if (code == BLE_NOT_SUPPORTED) {
                }
            }
        });
    }

    @Override
    public boolean isConnetBle() {
        if (null == mClient || TextUtils.isEmpty(connDeviceAddress)) {
            return false;
        }
        int status = mClient.getConnectStatus(connDeviceAddress);
        return status == STATUS_DEVICE_CONNECTED;
    }

    @Override
    public void setPin(Class btClass, BluetoothDevice btDevice, String str) {
        try {
            ClsUtils.setPairingConfirmation(btDevice.getClass(), btDevice, true);
            ClsUtils.setPin(btClass, btDevice, str);
            ClsUtils.cancelPairingUserInput(btClass, btDevice);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void setPin(String str) {
        if (mClient == null) {
            return;
        }
        BluetoothDevice device = null;
        for (BleDevice bleDevice : deviceList) {
            if (bleDevice.deviceAddress.equals(str)) {
                device = bleDevice.device;
                break;
            }
        }
        if (device != null) {
            setPin(BluetoothDevice.class, device, str);
        }
    }

    @Override
    public void disConnetBle() {
        if (mClient == null) {
            return;
        }

        BleDevice conDevice = null;
        for (BleDevice device : deviceList) {
            if (TextUtils.equals(device.deviceAddress, connDeviceAddress)) {
                conDevice = device;
                break;
            }
        }
        if (null != conDevice) {
            mClient.unregisterConnectStatusListener(connDeviceAddress, mBleConnectStatusListener);
            mClient.disconnect(connDeviceAddress);
            conDevice.isConnect = false;
            connDeviceAddress = "";
            if (autoLimit != null && autoLimit.isNeedAutoConnect()) {
                ICaneBleApi.getInstance().setHandshake(false);
            }
            if (null != iBleListener) {
                iBleListener.onDisConnect(conDevice);
            }
        }

    }

    @Override
    public void autoConnetBle() {
        if (mClient == null) {
            return;
        }
        if (autoLimit == null || !autoLimit.isNeedAutoConnect()) {
            return;
        }

        LogUtil.i("@hzy", "autoConnetBle----------" + deviceList.size());
        BleDevice bleDevice = null;
        for (BleDevice device : deviceList) {
            int maxAutoDevice = autoLimit.getMaxAutoCount();
//            if (maxAutoDevice == 0) {
//                bleDevice = getNextDevice();
//            } else {
            for (int i = 0; i < maxAutoDevice; i++) {
                bleDevice = autoLimit.getNextAutoDevice();
                if (bleDevice != null && TextUtils.equals(bleDevice.deviceAddress, device.deviceAddress)) {
                    break;
                }
                bleDevice = null;
            }
//            }
            if (bleDevice != null) {
                connetBle(device.deviceAddress);
                break;
            }
        }
        mHandler.removeMessages(CLOSE_BLE);
        mHandler.sendEmptyMessageDelayed(CLOSE_BLE, 15000);
    }

//    private BleDevice getNextDevice() {
//        BleDevice nextDevice = null;
//        for (BleDevice bleDevice : deviceList) {
//            if (!isConedList.contains(bleDevice)) {
//                nextDevice = bleDevice;
//                break;
//            }
//        }
//        if (null != nextDevice) {
//            isConedList.add(nextDevice);
//        }
//        return nextDevice;
//    }

    @Override
    public String readRssi() {
        mClient.readRssi(connDeviceAddress, new BleReadRssiResponse() {
            @Override
            public void onResponse(int i, Integer integer) {
                String temp = String.valueOf(integer);
                if (!TextUtils.isEmpty(temp)) {
                    mConnRssi = temp;
                }
            }
        });
        if (TextUtils.isEmpty(mConnRssi)) {
            for (BleDevice bleDevice : deviceList) {
                if (TextUtils.equals(bleDevice.deviceAddress, connDeviceAddress)) {
                    if (!TextUtils.isEmpty(bleDevice.deviceRssi)) {
                        mConnRssi = bleDevice.deviceRssi;
                    }
                }
            }
        }
        return mConnRssi;
    }

    @Override
    public void setCharacteristic(BluetoothGattCharacteristic characteristic) {
        if (mClient == null) {
            return;
        }
    }

    private BleNotifyResponse mBleNotify;

    @Override
    public void writeBle(String serviceUUIDstr, String characteristicUUIDstr, final byte[] value) {
        if (mClient == null) {
            return;
        }
        UUID serviceUUID = UUID.fromString(serviceUUIDstr);
        UUID characterUUID = UUID.fromString(characteristicUUIDstr);
        if (mBleNotify == null) {
            mBleNotify = new BleNotifyResponse() {
                @Override
                public void onNotify(UUID service, UUID character, byte[] value) {
                    //处理通知返回的数据
                    Log.i("@hzy", "onNotify-----" + HexStringUtil.bytesToHexString(value));
                    ICaneBleApi.getInstance().analysis(value);
                }

                @Override
                public void onResponse(int code) {
                    if (code == REQUEST_SUCCESS) {
                        Log.i("@hzy", "onNotify-----REQUEST_SUCCESS");
                    }
                }
            };
        }
        try {
            if (mBleNotify != null) {
                mClient.unnotify(connDeviceAddress, serviceUUID, characterUUID, new BleUnnotifyResponse() {
                    @Override
                    public void onResponse(int i) {

                    }
                });
            }
        } catch (Exception e) {

        }
        mClient.notify(connDeviceAddress, serviceUUID, characterUUID, mBleNotify);

        mClient.writeNoRsp(connDeviceAddress, serviceUUID, characterUUID, value, new BleWriteResponse() {
            @Override
            public void onResponse(int code) {
                if (code == REQUEST_SUCCESS) {
                    //处理通知返回的数据
                    Log.i("@hzy", "write-----" + HexStringUtil.bytesToHexString(value));
                }
            }
        });
//        mClient.writeDescriptor(connDeviceAddress, serviceUUID, characterUUID, UUID.fromString(SERVICE_D),value, new BleWriteResponse() {
//            @Override
//            public void onResponse(int code) {
//                if (code == REQUEST_SUCCESS) {
//                    //处理通知返回的数据
//                    Log.i("@hzy", "writeDescriptor-----" + HexStringUtil.bytesToHexString(value));
//                }
//            }
//        });
//        mClient.read(connDeviceAddress, serviceUUID, characterUUID, new BleReadResponse() {
//            @Override
//            public void onResponse(int code, byte[] data) {
//                if (code == REQUEST_SUCCESS) {
//                    //处理通知返回的数据
//                    Log.i("@hzy", "read-----" + HexStringUtil.bytesToHexString(data));
//                    ICaneBleApi.getInstance().analysis(data);
//                }
//            }
//        });
    }

    @Override
    public void closeBle() {
        if (mClient == null) {
            return;
        }
        mClient.unregisterBluetoothBondListener(mBluetoothBondListener);
        mClient.unregisterBluetoothStateListener(mBluetoothStateListener);
//        if (mClient.isBluetoothOpened()) {
//            mClient.closeBluetooth();
//        }
    }

    @Override
    public void register(IHandler i) {
        mHandler.register(i);
    }

    @Override
    public void unRegister(IHandler i) {
        mHandler.unRegister(i);
    }

    //配对状态
    private final BluetoothBondListener mBluetoothBondListener = new BluetoothBondListener() {
        @Override
        public void onBondStateChanged(String mac, int bondState) {
            // bondState = Constants.BOND_NONE, BOND_BONDING, BOND_BONDED
        }
    };
    //连接状态
    private final BleConnectStatusListener mBleConnectStatusListener = new BleConnectStatusListener() {

        @Override
        public void onConnectStatusChanged(String mac, int status) {
            if (status == STATUS_CONNECTED) {
                connDeviceAddress = mac;
                if (null != iBleListener) {
                    BleDevice connectDevice = null;
                    for (BleDevice bleDevice : deviceList) {
                        if (TextUtils.equals(bleDevice.deviceAddress, connDeviceAddress)) {
                            bleDevice.isConnect = true;
                            connectDevice = bleDevice;
                            break;
                        }
                    }
                    if (null != connectDevice) {
                        iBleListener.onConnected(connectDevice);
                    }
                }
                mHandler.removeMessages(CLOSE_BLE);
                mHandler.removeMessages(CONNECTING);
                mHandler.sendEmptyMessage(CONNECTING);
            } else if (status == STATUS_DISCONNECTED) {
                openDisToast();
                BleDevice connectDevice = null;
                for (BleDevice bleDevice : deviceList) {
                    if (TextUtils.equals(bleDevice.deviceAddress, connDeviceAddress)) {
                        connectDevice = bleDevice;
                        break;
                    }
                }
                if (null != connectDevice) {
                    connectDevice.isConnect = false;
                    connDeviceAddress = "";
                    mConnRssi = "";
                    mHandler.removeMessages(DISCONNECTED);
                    mHandler.sendEmptyMessage(DISCONNECTED);
                    if (null != autoLimit && autoLimit.isNeedAutoConnect()) {
                        mHandler.removeMessages(CONNET_NEXT);
                        mHandler.sendEmptyMessage(CONNET_NEXT);
                    }
                    if (null != iBleListener) {
                        iBleListener.onDisConnect(connectDevice);
                    }
                }
            }
        }
    };
    /**
     * 蓝牙打开状态
     */
    private final BluetoothStateListener mBluetoothStateListener = new BluetoothStateListener() {
        @Override
        public void onBluetoothStateChanged(boolean openOrClosed) {
            if (openOrClosed) {
                mHandler.removeMessages(SERVICE_OPEN);
                mHandler.sendEmptyMessage(SERVICE_OPEN);
            } else {//主动断开连接
                openDisToast();
                if (!TextUtils.isEmpty(connDeviceAddress)) {
                    mClient.unregisterConnectStatusListener(connDeviceAddress, mBleConnectStatusListener);
                    mClient.disconnect(connDeviceAddress);
                }
                BleDevice conDevice = null;
                for (BleDevice device : deviceList) {
                    if (TextUtils.equals(device.deviceAddress, connDeviceAddress)) {
                        conDevice = device;
                        break;
                    }
                }
                if (null != conDevice) {
                    conDevice.isConnect = false;
                    connDeviceAddress = "";
                    mConnRssi = "";
                    if (autoLimit != null && autoLimit.isNeedAutoConnect()) {
                        ICaneBleApi.getInstance().setHandshake(false);
                    }
                    if (null != iBleListener) {
                        iBleListener.onDisConnect(conDevice);
                    }
                }
            }
            isOpen = openOrClosed;
        }

    };

    /**
     * 蓝牙设备断开连接提示
     */
    private void openDisToast() {
        if (null == autoLimit) {
            return;
        }
        List<BleDevice> bleDevices = autoLimit.getAutoDevices();
        if (bleDevices.size() < 0 || TextUtils.isEmpty(connDeviceAddress)) {
            return;
        }
        BleDevice noActiveDevice = null;
        for (BleDevice bleDevice : bleDevices) {
            if (TextUtils.equals(bleDevice.deviceAddress, connDeviceAddress)) {
                noActiveDevice = bleDevice;
                break;
            }
        }
        if (null != noActiveDevice) {
            if (autoLimit.isActiveBleDevice(noActiveDevice)) {
                autoLimit.setActiveBleDevice(noActiveDevice, false);
                if (AppForegroundStateManager.getInstance().isAppInForeground()) {
                    final Activity mContext = AppForegroundStateManager.getInstance().getForegroundActivity();
                    mContext.runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            ToastUtil.openBaseToast(mContext, R.string.ble_disconnect_toast, Toast.LENGTH_SHORT);
                        }
                    });
                }
            }
        }
    }


}
